package lxs.swift;

import lxs.swift.collector.ImMut;
import lxs.swift.collector.Result;
import lxs.swift.collector.cache.list.ListCache;
import lxs.swift.collector.sync.Pool;
import lxs.swift.collector.sync.RwLock;
import lxs.swift.collector.wrap.Either;
import lxs.swift.collector.wrap.Option;
import lxs.swift.collector.wrap.Trouble;
import lxs.swift.operation.Flush;
import lxs.swift.operation.Try;
import lxs.swift.operation.match.Match;
import lxs.swift.tool.Sorter;
import lxs.swift.tool.acc.Acc;
import lxs.swift.tool.acc.Inlet;
import lxs.swift.tool.acc.Port;
import lxs.swift.tool.http.Config;
import lxs.swift.tool.http.Receiver;
import lxs.swift.tool.http.Sender;
import lxs.swift.verify.objectCheck.Check;
import lxs.swift.verify.objectCheck.Oc;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import static lxs.swift.operation.match.Item.*;


public class Main {
    public static class User {
        String name;
        Integer age;
        boolean isMale;

        public User(String name, Integer age, boolean isMale) {
            this.name = name;
            this.age = age;
            this.isMale = isMale;
        }

        public String name() {
            return name;
        }

        public Integer age() {
            return age;
        }

        public boolean isMale() {
            return isMale;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public void setMale(boolean male) {
            isMale = male;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", isMale=" + isMale +
                    '}';
        }
    }

    public static List<User> users() {
        return Arrays.asList(
                new User("foo", 18, true),
                new User("bar", 19, false),
                new User("foo1", 81, true),
                new User("bar1", 5, false),
                new User("foo2", 12, true),
                new User("bar2", 19, false)
        );
    }

    public static void testAcc() {
        Inlet<User> userInlet = new Inlet<>();

        Port<User, Long> maxAge = Port.bind(Acc.Int.max(u -> ((long) u.age)));
        userInlet.server(maxAge, (val) -> System.out.println("最大年龄：" + val));

        Port<User, List<String>> names = Port.bind(Acc.collect(new ArrayList<>(), User::name));
        userInlet.server(names, (val) -> System.out.println("全部人的名字：" + val));

        Port<User, Long> isMale = Port.bind(Acc.count(User::isMale));
        userInlet.server(isMale, (val) -> System.out.println("男生人数：" + val));

        Port<User, Long> ageSum = Port.bind(Acc.Int.sum(u -> ((long) u.age)));
        userInlet.server(ageSum, (val) -> System.out.println("总年龄：" + val));

        Port<User, User> maxAgeUser = Port.bind(Acc.<User, User, User>refreshLazy(Function.identity(), (in, state) -> in.age < state.age ? in : state, Function.identity()));
        userInlet.server(maxAgeUser, (val) -> System.out.println("年纪最小的人是：" + val));

        Port<User, Long> total = Port.bind(Acc.count((user) -> true));
        Port<User, Long> sync = total.sync();
        userInlet.server(sync, (val) -> System.out.println("总人数：" + val));

        users().forEach(userInlet::in);

        userInlet.notice();
        // 最大年龄：81
        // 全部人的名字：[foo, bar, foo1, bar1, foo2, bar2]
        // 男生人数：3
        // 总年龄：154
        // 年纪最小的人是：User{name='bar1', age=5, isMale=false}
        // 总人数：6
    }

    public static void testSort() {
        Sorter<User> userSorter = Sorter.create(User::age, User::name, User::isMale);
        Sorter.Rank<User> rank = userSorter.rank("age:desc", "name:asc");
        //  Sorter.Rank<User> rank = userSorter.rank(Sorter.desc(User::age), User::name);
        List<User> users = users();

        rank.sort(users);
        System.out.println(users);
    }

    public static void testInMut() {
        User user = new User("foo", 18, true);
        user.setAge(5);
        User u = ImMut.freeze(user);
        u.setAge(5);
    }

    public static void testRes() {
        Result<String> respond = Result.exec(() -> {
            int i = 1 / 0;
            return i + "";
        }).error((err) -> {
            throw new RuntimeException("bbb");
        }).onFinally(System.out::println).respond();
        System.out.println(respond);
    }

    public static void testOption() {
        Map<String, String> map = new HashMap<>();
        map.put("a", "a");
        Option<String> option = Option.of(() -> map.get("a"));
        System.out.println(option);
    }

    public static void testTry() {
        Try.runOf(() -> System.out.println(5 / 0)).then(() -> System.out.println(5 / 1)).caught(System.out::println).run();
        Try<Integer, RuntimeException> aTry = Try.valueOf(() -> 5 / 0);
        String aaa = aTry.then(Object::toString).caught(Throwable::toString).finalize(() -> {
            System.out.println(55555);
        }).ret();

        System.out.println(aaa);
        Integer ret = aTry.ret();
    }

    public static void testMatch() {
        {
            Option<Integer> some = Option.some(5);
            Integer i = some.matchMap(v -> 5 / 5, () -> 7);
            System.out.println(i);
        }
        {
            Trouble<Integer, Throwable> ok = Trouble.ok(5);
            String s = ok.matchMap(v -> v + "ok", v -> v + "err");
            System.out.println(s);
        }
        {
            Either<String, String> left = Either.left("5");
            left.matchRun(System.out::println, System.out::println);
        }

        String s = Match.from(1).of(
                $eq(1, "1"),
                $eq(2, "2"),
                $eq(3, "3"),
                $type(Integer.class, "class"),
//                $eq(6, (v) -> v + "1"),
                $("9")
        );
        System.out.println(s);
    }


    public static void testHttp() {
        String t = "charset=utf-8&notifyType=allinpay.yunst.orderService.pay&notifyTime=2024-06-05+10%3A39%3A41&appId=1581648210684&bizContent=%7B%22amount%22%3A450%2C%22orderNo%22%3A%221798182787757449216%22%2C%22termrefnum%22%3A%224200002189202406052101689336%22%2C%22channelFee%22%3A%221%22%2C%22channelPaytime%22%3A%222024-06-05+10%3A39%3A30%22%2C%22extendInfo%22%3A%22%7B%5C%22orderSn%5C%22%3A%5C%22202406051289273%5C%22%2C%5C%22customerId%5C%22%3A%5C%229999999%5C%22%7D%22%2C%22accttype%22%3A%2299%22%2C%22chnltrxid%22%3A%224200002189202406052101689336%22%2C%22payInterfaceOutTradeNo%22%3A%22240605127888141709%22%2C%22buyerBizUserId%22%3A%2263b2183f245ad799353ca43f270cf5e1%22%2C%22termauthno%22%3A%22OTHERS%22%2C%22cusid%22%3A%2266073105193205M%22%2C%22payInterfacetrxcode%22%3A%22VSP501%22%2C%22channelExtendInfo%22%3A%7B%22trxAmt%22%3A%22450%22%7D%2C%22payDatetime%22%3A%222024-06-05+10%3A39%3A31%22%2C%22acct%22%3A%22om5up4iSO6t67yKfWfKhRITEmYTg%22%2C%22bizOrderNo%22%3A%22202406051289273%22%2C%22status%22%3A%22OK%22%7D&sign=WqJub1LGDoNEmkaN28aUpKEH8hbfXBqByCLXIDBsnjKMDUeDVqg%2BKO3lowN0t3XMHTFZCQO%2FOxQGmeoSZgxWvzhrQ0zS%2BpH7NK75w2RVJUUgry1uHxI6fBGYeAjyoBILgE2bu8fQ40Z2%2FKJyYsJbr22z4vOUhGMKgVKLTM3kctGccENAPvkY6dooh%2FcQByz0ocwPffptK54FZBE1jLbznfSvVF6cGbXZmObtJTH8lrYO%2Fr6LP%2BZZR2my%2BLfAegU8K8Tx%2BdxTZbLHy3vePSPHnRnSyIlw4TNVL8kEYWNc2JSK8g4BY1mJi5%2Bk72ib3ST8CmOujmfppL3v91xMU5Oh4g%3D%3D&signType=SHA256WithRSA&notifyId=1798182837443522561&version=1.0";
        Sender sender = Sender.config(Config
                .of("https://hsjapi-test.ynhuashengjin.com/tl/app/api/pay/tlNotify")
                .method("POST")).sender();
        sender.write(t.getBytes(StandardCharsets.UTF_8));
        Receiver receiver = sender.read();
        String content = receiver.content();
        System.out.println(content);
    }


    public static void testCache() {
//        Try.run(() -> Thread.sleep(100)).run();
        ListCache<User> cache = ListCache.<User>builder("foo")
                                         .dataSupplier(() -> {
                                             System.out.println("更新");
                                             List<User> users = users();
                                             Try.runOf(() -> Thread.sleep(100)).run();
                                             return users;
                                         })
                                         .list(new ArrayList<>())
                                         .overTime(2)
                                         .build();
        List<User> select = cache.select((user -> user.isMale));
        Try.runOf(() -> Thread.sleep(5)).run();
        select = cache.select((user -> user.isMale));
        System.out.println(select);
    }

//    private static final ExecutorService executorService = Executors.newFixedThreadPool(50);

    private static void runTask(long intervalTime, Collection<Runnable> runs) {
        CountDownLatch latch = new CountDownLatch(runs.size());
        for (Runnable run : runs) {
            new Thread(() -> {
                try {
                    run.run();
                } finally {
                    latch.countDown();
                }
            }).start();

            Try.runOf(() -> Thread.sleep(intervalTime)).run();
        }
        try {
            latch.await();
//            executorService.shutdown();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void testRwLock() {
        RwLock<User> user = new RwLock<>(new User("foo", 18, true));
        runTask(1, Arrays.asList(() -> user.writeSoftSet((old) -> {
            System.out.println(Thread.currentThread().getName() + ":run");
            Try.runOf(() -> Thread.sleep(1000)).run();
            return old;
        }), () -> user.writeSoftSet((old) -> {
            System.out.println(Thread.currentThread().getName() + ":run");
            Try.runOf(() -> Thread.sleep(100)).run();
            return old;
        })));
    }

    public static void testPool() {

//        Pool<Integer> pool = Pool.fixed(1, 2, 3);
        AtomicInteger atomicInteger = new AtomicInteger(0);
        Pool<Integer> pool = Pool.factory(atomicInteger::getAndIncrement, 50,10, TimeUnit.MINUTES,30*1000);
        List<Runnable> runnables = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            runnables.add(() -> {
                String s = pool.get(v -> {
                    System.out.println("&" + LocalDateTime.now() + "=" + finalI + "---" + v);
                    Try.runOf(() -> Thread.sleep(100)).run();
                    return v + "";
                });
                System.out.println(LocalDateTime.now() + "=" + finalI + "-" + s);
            });
        }
        runTask(1000, runnables);
    }

    public static void testWrapper() {
        try {
            {
                Trouble<String, Throwable> foo = Trouble.ok("foo");
                foo.unwrap();
                System.out.println(foo);

                foo = Trouble.err(new RuntimeException("aaa"));
                System.out.println(foo);

                Trouble<Integer, Throwable> ok = Trouble.ok(150);
                System.out.println(ok);
            }
            {
                Option<String> bar = Option.some("bar");
                System.out.println(bar);
                bar = Option.none();
                System.out.println(bar);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void testFlush() {
        User user = new User("a", 0, false);

        System.out.println(user);
        {
            Flush.IntFlush flush = Flush.ofInt(user::age, user::setAge);
            flush.acc(1);
            flush.swapNew(v -> v + 1);
            flush.swapNew(v -> v + 1);
            flush.swapNew(v -> v + 1);
            flush.swapNew(v -> v + 1);
            flush.swapNew(v -> v + 1);
        }
        System.out.println(user);
    }

    public static void testOc() {
        {
            Oc<Integer> oc = Oc.of(1).nullReplace(5);
            oc.all(
                    Check.isNull(),
                    Check.isEmpty(),
                    Check.isDefault(),
                    v -> v.toString().endsWith("1")
            ).unexpected(new RuntimeException("foo"));
        }
        {
            Oc.of("").all(Check.isNull(), Check.isWrap("", ""), Check.isGt("52")).negate().expected(new RuntimeException("bar"));
        }
    }

    public static void main(String[] args) {
//        testAcc();
//        testSort();
//        testRes();
//        testTry();
//        testMp();
//        testHttp();
        testPool();
//        testFlush();
//        testMatch();
//        testOc();
//        testWrapper();


//        testCache();
//        testOption();
//        testMatch();
//        testRwLock();
//        testInMut();


//        String str = "6E79706537383965466";
//        String regex = "(.{2})"; //两位两位分割
//        str = str.replaceAll(regex, "$1,");
//        StringBuffer res = new StringBuffer();
//        String[] list = str.split(","); //转换数组
//        for (int i = 0; i < list.length - 1; i++) {  //拼接askll码
//            res.append((char) (Integer.parseInt(list[i], 16) - Integer.parseInt(list[list.length - 1], 16)));
//        }
//        System.out.println(str);
//        System.out.println(res);

    }


}
